﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net;
using System.Net.Sockets;

namespace P2PChat.Net
{
    /// <summary>
    /// 简单的侦听类
    /// </summary>
    public class Listener
    {
        IPAddress localAddress;
        /// <summary>
        /// 监听的IP地址
        /// </summary>
        public IPAddress LocalAddress
        {
            get { return localAddress; }
            set { localAddress = value; }
        }

        int port;
        /// <summary>
        /// 监听的端口
        /// </summary>
        public int Port
        {
            get { return port; }
            set { port = value; }
        }

        TcpListener listener;

        bool isExit = false;
        /// <summary>
        /// 获取是否已经退出的状态。
        /// </summary>
        public bool IsExit { get { return isExit; } }

        bool isStarted = false;
        /// <summary>
        /// 获取侦听行为是否已经启动。
        /// </summary>
        public bool IsStarted { get { return isStarted; } }

        /// <summary>
        /// 负责日志的行为
        /// </summary>
        public P2PChat.Log.ILog log;
        /// <summary>
        /// 当有客户端连接传入时触发此事件
        /// </summary>
        public event EventHandler<ListenerEventArgs> ClientConnect;

        /// <summary>
        /// 使用IP地址和端口号初始化侦听类
        /// </summary>
        /// <param name="ipAddress">IP地址</param>
        /// <param name="port">端口号</param>
        public Listener(string ipAddress, int port)
        {
            localAddress = IPAddress.Parse(ipAddress);
            Port = port;

            listener = new TcpListener(LocalAddress, Port);

        }

        /// <summary>
        /// 开启侦听状态
        /// </summary>
        public void Listen()
        {
            listener = new TcpListener(localAddress, port);
            try
            {
                listener.Start();
            }
            catch (SocketException ex)
            {
                if (log != null) log.Add(string.Format("Error: {0}", ex.Message));
                throw ex;
            }
            if (log != null)
            {
                log.Add(string.Format("开始在{0}:{1}监听客户端", localAddress, port));
            }
            System.Threading.Thread listeningThread = new System.Threading.Thread(ListeningFunction);
            listeningThread.Start();
            isStarted = true;
        }

        /// <summary>
        /// 停止侦听状态
        /// </summary>
        public void Stop()
        {
            listener.Stop();
            isStarted = false;
            if (log != null)
            {
                log.Add(string.Format("已经停止监听状态事件！"));
            }
        }

        #region [线程] 侦听行为 - 这个区域的内容和上部分处于不同的线程
        
        /// <summary>
        /// 
        /// </summary>
        private void ListeningFunction()
        {
            TcpClient incomingClient = null;
            while (isStarted)
            {
                ListenClientDelegate d = new ListenClientDelegate(ListenClient);
                IAsyncResult result = d.BeginInvoke(out incomingClient, null, null);
                // 使用轮询方式判断异步操作是否完成
                while (result.IsCompleted == false)
                {
                    if (IsExit)
                    {
                        break;
                    }
                    System.Threading.Thread.Sleep(250);
                }

                // 获取返回值和所有输入输出参数
                d.EndInvoke(out incomingClient, result);

                if (incomingClient != null)
                {
                    if (log != null)
                    {
                        log.Add(string.Format("已接受{0}的连接", incomingClient.Client.RemoteEndPoint));
                    }

                    if (ClientConnect != null)
                    {
                        ListenerEventArgs eventArgs = new ListenerEventArgs(incomingClient);
                        ClientConnect(this, eventArgs);
                    }
                }
            }
        }

        private delegate void ListenClientDelegate(out TcpClient client);
        /// <summary>
        /// 接受挂起的客户端连接请求
        /// </summary>
        /// <param name="incomingClient">接受的客户端</param>
        private void ListenClient(out TcpClient incomingClient)
        {
            try
            {
                incomingClient = listener.AcceptTcpClient();
            }
            catch
            {
                incomingClient = null;
            }
        }
        
        #endregion
    }
}
